﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;
using System.Threading;

namespace XTYAPI.通讯
{
    public class ModbusRTU
    {
        /// <summary>
        /// 串口对象
        /// </summary>
        public SerialPort SerialPort { get; private set; }
        /// <summary>
        /// 串口状态
        /// </summary>
        public bool IsOpen { get { return SerialPort != null && SerialPort.IsOpen; } }
        /// <summary>
        /// 超时时间
        /// </summary>
        public uint TimeOut { get; set; } = 200;
        /// <summary>
        /// 加锁对象
        /// </summary>
        readonly object lockModbus = new object();
        /// <summary>
        /// 打开串口号
        /// </summary>
        /// <param name="portName"></param>
        /// <param name="baudRate"></param>
        /// <param name="parity"></param>
        /// <param name="dataBis"></param>
        /// <param name="stopBits"></param>
        /// <returns></returns>
        public bool Open(string portName, int baudRate = 9600, Parity parity = Parity.None, int dataBis = 8, StopBits stopBits = StopBits.One)
        {
            try
            {
                SerialPort = new SerialPort(portName, baudRate, parity, dataBis, stopBits);
                SerialPort.Open();
                return SerialPort.IsOpen;
            }
            catch (Exception ex)
            {
                //
                return false;
            }
        }
        public bool Close()
        {
            SerialPort.Close();
            return SerialPort.IsOpen;
        }
        /// <summary>
        /// 获取串口号
        /// </summary>
        /// <returns></returns>
        public string[] GetPortNames()
        {
            return SerialPort.GetPortNames();
        }
        /// <summary>
        /// 01功能码 读线圈 0区
        /// </summary>
        /// <param name="deviveId">站地址</param>
        /// <param name="address">数据地址</param>
        /// <param name="count">要读的线圈数量</param>
        /// <returns></returns>
        public bool[] ReadCoil(int deviceId, int address, int count)
        {
            /* 0xf123
             * H:用来表示高8位
             * L:用来表示低8位
             * 发送ADU 站地址+01+起始地址(H L)+线圈数量(H L)+CRC校验(L H)               
             * 响应ADU 站地址+01+字节数+内容+CRC校验(低8位高8位)
             */
            if (count > 2000) return null;
            byte[] send = new byte[8];
            send[0] = (byte)deviceId;
            send[1] = 0x01;

            send[2] = (byte)(address >> 8);//获取高8位
            send[3] = (byte)(address & 0xff);//获取低8位

            send[4] = (byte)(count >> 8);//获取高8位
            send[5] = (byte)(count & 0xff);//获取低8位
            int reciveCount = count / 8 + (count % 8 > 0 ? 1 : 0);//计算数据区要回复的字节数
            byte[] reciveArray = SendRecive(CalSendCRC(send), 5 + reciveCount);
            bool crc = CalRecCRC(reciveArray);
            if (crc && //CRC OK
                reciveArray.Length == 5 + reciveCount &&//接收长度OK
                reciveArray[0] == send[0] &&//判断站地址是否一致
                reciveArray[1] == send[1]//判断功能码是否一致 
                )
            {
                byte[] data = new byte[reciveCount];
                bool[] bit = new bool[count];
                Array.Copy(reciveArray, 3, data, 0, data.Length);
                for (int i = 0; i < bit.Length; i++)
                {
                    int k = i / 8;
                    int b = i % 8;
                    bit[i] = (data[k] & (1 << b)) > 0;
                }
                return bit;
            }
            return null;
        }
        /// <summary>
        /// 01功能码 读线圈 0区异步
        /// </summary>
        /// <param name="deviveId">站地址</param>
        /// <param name="address">数据地址</param>
        /// <param name="count">要读的线圈数量</param>
        /// <returns></returns>
        public async Task<bool[]> AsyncReadCool(int deviceId, int address, int count)
        {
            return await Task.Run(() => { return ReadCoil(deviceId, address, count); });
        }

        /// <summary>
        /// 02功能码 读输入 1区
        /// </summary>
        /// <param name="deviveId">站地址</param>
        /// <param name="address">数据地址</param>
        /// <param name="count">要读的输入数量</param>
        /// <returns></returns>
        public bool[] ReadInput(int deviceId, int address, int count)
        {
            /* 0xf123
             * H:用来表示高8位
             * L:用来表示低8位
             * 发送ADU 站地址+02+起始地址(H L)+输入数量(H L)+CRC校验(L H)               
             * 响应ADU 站地址+02+字节数+内容+CRC校验(低8位高8位)
             */
            if (count > 2000) return null;
            byte[] send = new byte[8];
            send[0] = (byte)deviceId;
            send[1] = 0x02;

            send[2] = (byte)(address >> 8);//获取高8位
            send[3] = (byte)(address & 0xff);//获取低8位

            send[4] = (byte)(count >> 8);//获取高8位
            send[5] = (byte)(count & 0xff);//获取低8位
            int reciveCount = count / 8 + (count % 8 > 0 ? 1 : 0);//计算数据区要回复的字节数
            byte[] reciveArray = SendRecive(CalSendCRC(send), 5 + reciveCount);
            bool crc = CalRecCRC(reciveArray);
            if (crc && //CRC OK
                reciveArray.Length == 5 + reciveCount &&//接收长度OK
                reciveArray[0] == send[0] &&//判断站地址是否一致
                reciveArray[1] == send[1]//判断功能码是否一致 
                )
            {
                byte[] data = new byte[reciveCount];
                bool[] bit = new bool[count];
                Array.Copy(reciveArray, 3, data, 0, data.Length);
                for (int i = 0; i < bit.Length; i++)
                {
                    int k = i / 8;
                    int b = i % 8;
                    bit[i] = (data[k] & (1 << b)) > 0;
                }
                return bit;
            }
            return null;
        }
        /// <summary>
        /// 02功能码 读输入 1区 异步
        /// </summary>
        /// <param name="deviveId">站地址</param>
        /// <param name="address">数据地址</param>
        /// <param name="count">要读的输入数量</param>
        /// <returns></returns>
        public async Task<bool[]> AsyncReadInput(int deviceId, int address, int count)
        {
            return await Task.Run(() => { return ReadInput(deviceId, address, count); });
        }

        /// <summary>
        /// 03功能码 读保持寄存器 4区
        /// </summary>
        /// <param name="deviveId">站地址</param>
        /// <param name="address">寄存器地址</param>
        /// <param name="count">读多少个寄存器(16位)</param>
        /// <returns></returns>
        public byte[] ReadHoldingRegister(int deviceId, int address, int count)
        {
            /*03功能码 读保持寄存器
              发送ADU 站地址+03+起始地址(高8位低8位)+读取字的数量(高8位低8位)+CRC校验(低8位高8位)
              响应ADU 站地址+03+读取字节数 内容(高8位低8位)...+CRC校验(低8位高8位)
              读取数量 一般情况下是支持125个字，但是实际的数量要根据从站的限制来设定。
              异常ADU 站地址+0x83+异常码
              */
            if (count > 125)
            {
                return null;
            }
            byte[] send = new byte[8];
            send[0] = (byte)deviceId;
            send[1] = 0x03;

            send[2] = (byte)(address >> 8);//获取高8位
            send[3] = (byte)(address & 0xff);//获取低8位

            send[4] = (byte)(count >> 8);//获取高8位
            send[5] = (byte)(count & 0xff);//获取低8位
            byte[] recive = SendRecive(CalSendCRC(send), 5 + count * 2);
            bool crc = CalRecCRC(recive);
            if (crc &&//crcOK
                recive.Length == 5 + count * 2 &&//长度
                recive[0] == send[0] &&//站地址
                recive[1] == send[1]//功能码
                )
            {
                byte[] data = new byte[count * 2];
                Array.Copy(recive, 3, data, 0, data.Length);
                return data;
            }
            return null;
        }
        /// <summary>
        /// 03功能码 读保持寄存器 4区 异步
        /// </summary>
        /// <param name="deviveId">站地址</param>
        /// <param name="address">寄存器地址</param>
        /// <param name="count">读多少个寄存器(16位)</param>
        /// <returns></returns>
        public async Task<byte[]> AsyncReadHoldingRegister(int deviceId, int address, int count)
        {
            return await Task.Run(() => { return ReadHoldingRegister(deviceId, address, count); });
        }

        /// <summary>
        /// 04功能码 读输入寄存器 3区
        /// </summary>
        /// <param name="deviveId"></param>
        /// <param name="address"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public byte[] ReadInputRegister(int deviceId, int address, int count)
        {
            /*04功能码 读输入寄存器
              发送ADU 站地址+04+起始地址(高8位低8位)+读取字的数量(高8位低8位)+CRC校验(低8位高8位)
              响应ADU 站地址+04+读取字节数 内容(高8位低8位)...+CRC校验(低8位高8位)
              读取数量 一般情况下是支持125个字，但是实际的数量要根据从站的限制来设定。
              异常ADU 站地址+0x84+异常码
              */
            if (count > 125)
            {
                return null;
            }
            byte[] send = new byte[8];
            send[0] = (byte)deviceId;
            send[1] = 0x04;

            send[2] = (byte)(address >> 8);//获取高8位
            send[3] = (byte)(address & 0xff);//获取低8位

            send[4] = (byte)(count >> 8);//获取高8位
            send[5] = (byte)(count & 0xff);//获取低8位
            byte[] recive = SendRecive(CalSendCRC(send), 5 + count * 2);
            bool crc = CalRecCRC(recive);
            if (crc &&//crcOK
                recive.Length == 5 + count * 2 &&//长度
                recive[0] == send[0] &&//站地址
                recive[1] == send[1]//功能码
                )
            {
                byte[] data = new byte[count * 2];
                Array.Copy(recive, 3, data, 0, data.Length);
                return data;
            }
            return null;
        }

        /// <summary>
        /// 04功能码 读输入寄存器 3区异步
        /// </summary>
        /// <param name="deviveId"></param>
        /// <param name="address"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public async Task<byte[]> AsyncReadInputRegister(int deviceId, int address, int count)
        {
            return await Task.Run(() => { return ReadInputRegister(deviceId, address, count); });
        }

        /// <summary>
        /// 05功能码 写线圈 0区
        /// </summary>
        /// <param name="deviveId"></param>
        /// <param name="address"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        public bool WriteCoil(int deviceId, int address, bool state)
        {
            /*发送ADU 站地址+05+起始地址(高8位低8位)+线圈状态(高8位 低8位)+CRC校验(低8位高8位)
              接收ADU 站地址+05+起始地址(高8位低8位)+线圈状态(高8位 低8位)+CRC校验(低8位高8位)
              异常ADU 站地址+0x85+异常码        
             */
            byte[] send = new byte[8];
            send[0] = (byte)deviceId;
            send[1] = 0x05;

            send[2] = (byte)(address >> 8);//获取高8位
            send[3] = (byte)(address & 0xff);//获取低8位

            send[4] = (byte)(state ? 0xff : 0x00);//写线圈状态
            send[5] = 0x00;

            byte[] recive = SendRecive(CalSendCRC(send), 8);
            bool crc = CalRecCRC(recive);
            if (crc && recive.Length == 8 &&
                 recive[0] == send[0] &&//站地址
                recive[1] == send[1]//功能码
                )
            {
                return true;
            }
            return false;
        }
        /// <summary>
        /// 05功能码 写线圈 0区 异步
        /// </summary>
        /// <param name="deviveId"></param>
        /// <param name="address"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        public async Task<bool> AsyncWtiteCoil(int deviceId, int address, bool state)
        {
            return await Task.Run(() => { return WriteCoil(deviceId, address, state); });
        }

        /// <summary>
        /// 06功能码 写单个保持寄存器 4区
        /// </summary>
        /// <param name="deviceId">站地址</param>
        /// <param name="address">寄存器地址</param>
        /// <param name="value">要写的值</param>
        /// <returns></returns>
        public bool WriteHoldingRegister(int deviceId, int address, short value)
        {
            /*06功能码 写保持寄存器
              发送ADU 站地址+06+寄存器地址(高8位低8位)+寄存器值(高8位 低8位)+CRC校验(低8位高8位)
              接收ADU 站地址+06+寄存器地址(高8位低8位)+寄存器值(高8位 低8位)+CRC校验(低8位高8位)
              异常ADU 站地址+0x86+异常码
             */
            byte[] send = new byte[8];

            send[0] = (byte)deviceId;
            send[1] = 0x06;

            send[2] = (byte)(address >> 8);//获取高8位
            send[3] = (byte)(address & 0xff);//获取低8位

            byte[] bs = BitConverter.GetBytes(value);
            send[4] = bs[1];
            send[5] = bs[0];

            byte[] recive = SendRecive(CalSendCRC(send), 8);
            bool crc = CalRecCRC(recive);
            if (crc && recive.Length == 8 &&
                 recive[0] == send[0] &&//站地址
                recive[1] == send[1]//功能码
                )
            {
                return true;
            }
            return false;
        }
        /// <summary>
        /// 06功能码 写单个保持寄存器 4区 异步
        /// </summary>
        /// <param name="deviceId">站地址</param>
        /// <param name="address">寄存器地址</param>
        /// <param name="value">要写的值</param>
        /// <returns></returns>
        public async Task<bool> AsyncWriteHoldingRegister(int deviceId, int address, short value)
        {
            return await Task.Run(() => { return WriteHoldingRegister(deviceId, address, value); });
        }

        /// <summary>
        /// 15 功能码 写从起始地址开始的连续线圈状态 0区
        /// </summary>
        /// <param name="deviceId"></param>
        /// <param name="address"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        public bool WriteCoil(int deviceId, int address, bool[] state)
        {
            /*15(0x0f)功能码 写从起始地址开始的连续线圈状态
              发送ADU 站地址+0xf+起始线圈地址(高8位低8位)+线圈的数量(高8位 低8位)+线圈的字节数N+内容+CRC校验(低8位高8位)
              接收ADU 站地址+0xf+起始线圈地址(高8位低8位)+线圈的数量(高8位 低8位)+CRC校验(低8位高8位)
              异常ADU 站地址+0x8f+异常码+CRC校验(低8位高8位)
              线圈的字节数N=线圈的数量/8 如果不能整除有余数则字节数量再加1，没有用到的位用0补齐
             */
            if (state.Length > 1968) return false;
            //计算要发送的字节数量
            byte byteCount = (byte)(state.Length / 8 + (state.Length % 8 > 0 ? 1 : 0));
            byte[] send = new byte[9 + byteCount];
            send[0] = (byte)deviceId;
            send[1] = 0x0f;
            //线圈地址
            send[2] = (byte)(address >> 8);//获取高8位
            send[3] = (byte)(address & 0xff);//获取低8位
            //线圈数量
            send[4] = (byte)(state.Length >> 8);//获取高8位
            send[5] = (byte)(state.Length & 0xff);//获取低8位

            send[6] = byteCount;
            //计算数据区 字节与bit位赋值
            for (int i = 0; i < state.Length; i++)
            {
                //0000 0000      0000 0001     0000 0011 原数据
                //0000 0001 或   0000 0010     0000 0100 位权
                //0000 0001      0000 0011     1111 1011 取反
                //                             0000 0011 原数据和取反数据进行与

                int k = i / 8;//获得对应的字节偏移量
                int b = i % 8;//获得对应的bit位偏移量
                byte byte1 = send[7 + k];//获取对应的字节
                byte byte2 = (byte)(1 << b);//获取位权
                byte1 = state[i] ? (byte)(byte1 | byte2) : (byte)(byte1 & ~byte2);//true和false处理
                send[7 + k] = byte1;//把字节还回去
            }
            byte[] recive = SendRecive(CalSendCRC(send), 8);
            bool crc = CalRecCRC(recive);
            if (crc && recive.Length == 8 &&
                 recive[0] == send[0] &&//站地址
                recive[1] == send[1]//功能码
                )
            {
                return true;
            }
            return false;
        }
        /// <summary>
        /// 15 功能码 写从起始地址开始的连续线圈状态 0区异步
        /// </summary>
        /// <param name="deviceId"></param>
        /// <param name="address"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        public async Task<bool> AsyncWriteCoil(int deviceId, int address, bool[] state)
        {
            return await Task.Run(() => { return WriteCoil(deviceId, address, state); });
        }

        /// <summary>
        /// 16功能码 写从起始地址开始的连续保持寄存器 4区
        /// </summary>
        /// <param name="deviceId"></param>
        /// <param name="address"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool WriteHoldingRegister(int deviceId, int address, byte[] value)
        {
            /*16(0x10)功能码 写从起始地址开始的连续保持寄存器
              发送ADU 站地址+0x10+起始寄存器地址(高8位低8位)+寄存器的数量(高8位 低8位)+寄存器的字节数N+内容+CRC校验(低8位高8位)
              接收ADU 站地址+0x10+起始寄存器地址(高8位低8位)+寄存器的数量(高8位 低8位)+CRC校验(低8位高8位)
              异常ADU 站地址+0x90+异常码+CRC校验(低8位高8位)
             */
            ushort wordCount = (ushort)(value.Length / 2);
            if (wordCount > 123) return false;
            byte[] send = new byte[9 + wordCount * 2];
            send[0] = (byte)deviceId;
            send[1] = 0x10;
            //寄存器地址
            send[2] = (byte)(address >> 8);//获取高8位
            send[3] = (byte)(address & 0xff);//获取低8位
            //寄存器数量
            send[4] = (byte)(wordCount >> 8);//获取高8位
            send[5] = (byte)(wordCount & 0xff);//获取低8位
            //字节数量
            send[6] = (byte)(wordCount * 2);

            for (int i = 0; i < wordCount * 2; i++)
            {
                send[7 + i] = value[i];
            }
            byte[] recive = SendRecive(CalSendCRC(send), 8);
            bool crc = CalRecCRC(recive);
            if (crc && recive.Length == 8 &&
                 recive[0] == send[0] &&//站地址
                recive[1] == send[1]//功能码
                )
            {
                return true;
            }
            return false;
        }
        /// <summary>
        /// 16功能码 写从起始地址开始的连续保持寄存器 4区异步
        /// </summary>
        /// <param name="deviceId"></param>
        /// <param name="address"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public async Task<bool> AsyncWriteHoldingRegister(int deviceId, int address, byte[] value)
        {
            return await Task.Run(() => { return WriteHoldingRegister(deviceId, address, value); });
        }

        /// <summary>
        /// 16功能码 写32位整形保持寄存器
        /// </summary>
        /// <param name="deviceId"></param>
        /// <param name="address"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool WriteHoldingRegister(int deviceId, int address, int value)
        {
            byte[] bs = BitConverter.GetBytes(value);
            byte[] send = new byte[4];
            send[0] = bs[3];
            send[1] = bs[2];
            send[2] = bs[1];
            send[3] = bs[0];
            return WriteHoldingRegister(deviceId, address, send);
        }
        /// <summary>
        /// 16功能码 写32位整形保持寄存器 异步
        /// </summary>
        /// <param name="deviceId"></param>
        /// <param name="address"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public async Task<bool> AysncWriteHoldingRegister(int deviceId, int address, int value)
        {
            return await Task.Run(()=> { return WriteHoldingRegister(deviceId, address, value); });
        }

        /// <summary>
        /// 16功能码 写32位浮点保持寄存器
        /// </summary>
        /// <param name="deviceId"></param>
        /// <param name="address"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool WriteHoldingRegister(int deviceId, int address, float value)
        {
            byte[] bs = BitConverter.GetBytes(value);
            byte[] send = new byte[4];
            send[0] = bs[3];
            send[1] = bs[2];
            send[2] = bs[1];
            send[3] = bs[0];
            return WriteHoldingRegister(deviceId, address, send);
        }
        /// <summary>
        /// 16功能码 写32位浮点保持寄存器
        /// </summary>
        /// <param name="deviceId"></param>
        /// <param name="address"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public async Task<bool> AysncWriteHoldingRegister(int deviceId, int address, float value)
        {
            return await Task.Run(()=> { return WriteHoldingRegister(deviceId, address, value); });
        }


        /// <summary>
        /// 16功能码 写64位整形保持寄存器
        /// </summary>
        /// <param name="deviceId"></param>
        /// <param name="address"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool WriteHoldingRegister64Bit(int deviceId, int address, long value)
        {
            byte[] bs = BitConverter.GetBytes(value);
            byte[] send = new byte[8];
            send[0] = bs[7];
            send[1] = bs[6];
            send[2] = bs[5];
            send[3] = bs[4];
            send[4] = bs[3];
            send[5] = bs[2];
            send[6] = bs[1];
            send[7] = bs[0];
            return WriteHoldingRegister(deviceId, address, send);
        }
        /// <summary>
        /// 16功能码 写64位整形保持寄存器 异步
        /// </summary>
        /// <param name="deviceId"></param>
        /// <param name="address"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public async Task<bool> AysncWriteHoldingRegister64Bit(int deviceId, int address, int value)
        {
            return await Task.Run(() => { return WriteHoldingRegister64Bit(deviceId, address, value); });
        }



        /// <summary>
        /// 16功能码 写64位浮点保持寄存器
        /// </summary>
        /// <param name="deviceId"></param>
        /// <param name="address"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool WriteHoldingRegister64Bit(int deviceId, int address, double value)
        {
            byte[] bs = BitConverter.GetBytes(value);
            byte[] send = new byte[8];
            send[0] = bs[7];
            send[1] = bs[6];
            send[2] = bs[5];
            send[3] = bs[4];
            send[4] = bs[3];
            send[5] = bs[2];
            send[6] = bs[1];
            send[7] = bs[0];
            return WriteHoldingRegister(deviceId, address, send);
        }
        /// <summary>
        /// 16功能码 写32位浮点保持寄存器
        /// </summary>
        /// <param name="deviceId"></param>
        /// <param name="address"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public async Task<bool> AysncWriteHoldingRegister64Bit(int deviceId, int address, double value)
        {
            return await Task.Run(() => { return WriteHoldingRegister64Bit(deviceId, address, value); });
        }

        private byte[] CalSendCRC(byte[] data)
        {
            /*（1）、预置1个16位的寄存器为十六进制FFFF（即全为1），称此寄存器为CRC寄存器；
            * （2）、把第一个8位二进制数据（既通讯信息帧的第一个字节）与16位的CRC寄存器的低 8位相异或，把结果放于CRC寄存器，高八位数据不变；
            * （3）、把CRC寄存器的内容右移一位（朝低位）用0填补最高位，并检查右移后的移出位；          
            * （4）、如果移出位为0：重复第3步（再次右移一位）；如果移出位为1，CRC寄存器与多项式（例如：1010 0000 0000 0001）进行异或0xa001；
            * （5）、重复步骤3和4，直到右移8次，这样整个8位数据全部进行了处理；
            * （6）、重复步骤2到步骤5，进行通讯信息帧下一个字节的处理；
            * （7）、将该通讯信息帧所有字节按上述步骤计算完成后，得到的16位CRC寄存器的高、低字节进行交换；
            * （8）、最后得到的CRC寄存器内容即为：CRC码。   
           */
            ushort crc = 0xffff;
            for (int i = 0; i < data.Length-2; i++)
            {
                crc =(ushort)(data[i] ^ crc);
                for (int k = 0; k < 8; k++)
                {
                    crc =(ushort)((crc & 1) == 1 ? (crc >> 1) ^ 0xa001 : (crc >> 1));
                }
            }
            data[data.Length - 2] =(byte) (crc & 0xff);//CRC低8位
            data[data.Length - 1] = (byte)(crc >> 8);//CRC高8位
            return data;
        }
        private bool CalRecCRC(byte[] data)
        {
            if (data==null||data.Length<=2)
            {
                return false;
            }
            //获取接收的CRC
            byte[] reciveCRC = new byte[] {data[data.Length-2], data[data.Length - 1] };
            CalSendCRC(data);//计算CRC
            //判断接收与计算的CRC是否相同
            bool crcOK = (reciveCRC[0] == data[data.Length - 2] )&& (reciveCRC[1] == data[data.Length - 1]);
            //返回CRC结果
            return crcOK;
        }
        /// <summary>
        /// 发送与接收
        /// </summary>
        /// <param name="array"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        private byte[] SendRecive(byte[] array,int count)
        {
            try
            {
                Monitor.Enter(lockModbus);
                SerialPort.Write(array, 0, array.Length);
                int timeOut = 0;
                while (SerialPort.BytesToRead < count && timeOut < TimeOut)
                {
                    Thread.Sleep(1);
                    timeOut++;
                }
                if (SerialPort.BytesToRead==0)
                {

                }
                byte[] resByte = new byte[SerialPort.BytesToRead];
                SerialPort.Read(resByte, 0, resByte.Length);
                return resByte;
            }
            catch (Exception)
            {

                return null;
            }
            finally 
            {
                Monitor.Exit(lockModbus);
            }
        }
    }
}
